<?php
class TICE_Controlador_Crud extends TICE_Controlador_Lista {
	
	/**
	 * Opções de upload
	 * @var {campo: opcoes {nome, caminho, validacoes}}
	 */
	public $uploads;
	/**
	 * A base do caminho para onde serão enviados os uploads 
	 * @var string
	 */
	public $caminho;
	public $urlUpload;
	/**
	 * O usuário logado naquel momento
	 * @var string
	 */
	public $usuario;
	
	function __construct(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response, array $invokeArgs = array() ) {
		parent::__construct($request, $response, $invokeArgs);
	}
	
	function preDispatch() {
		parent::preDispatch();
		$this->addPastaView('crud', array_search('lista', $this->view->getPastasView()));

		//$this->usuario = $this->view->layout()->identity;
		$this->usuario = Zend_Auth::getInstance()->getIdentity();
		
		if (empty($this->caminho)) {
			$this->urlUpload = $this->view->baseUrl('arquivos') . '/';
			$this->caminho = realpath('arquivos') . '/';
		}
		$this->view->urlUpload = $this->urlUpload;
		$this->view->caminho = $this->caminho;
	}

    public function indexAction()
    {
    }
    
    /**
	 * Cria um registro do modelo a ser inserido
	 * Trata uploads, se definidos no atributo $this->uploads
	 * @param array $_POST
	 * @return bean $registro
	 */
	protected function getBean($id = 0) {
		$campos = array();
		foreach ($this->_getAllParams() as $campo => $v) {
			$valor = $this->_getParam($campo);
			$campos[$campo] = (is_string($valor)) ? trim($valor) : $valor;
		}
		unset($campos['module']);unset($campos['controller']);unset($campos['action']);unset($campos['view']);
		if (!empty($id)) {
			$campos[$this->pk] = $id;
		}
		// se tiver, lida os uploads	
		if (!empty($this->uploads)) {
			// TODO: conferir apagar uploads
			// TODO: conferir edição uploads
			$this->beforeUpload($campos);
//			new d($campos); die;
			$this->trataUploads($campos, $id);
		}
		return $campos;
	}
	/**
	 * Mostra o formulário para inserção/edição
	 * @param int $_GET['id']
	 */
	public function formAction() {
		$pk = $this->pk;
		$this->veAction();
		if (empty($this->view->$pk)) {
			$this->view->action = $this->view->url . 'insere?';
		}
		else {
			$this->view->action = $this->view->url . 'edita?' . $pk . '=' . $this->view->$pk;
		}
	}
	/**
	 * Insere um registro (Template method)
	 * @param array $campos Os campos de trataForm()
	 * @return
	 * 		int $this->view->id,
	 * 		bool $this->view->resultado,
	 * 		string $this->view->msg
	 */
	public final function insereAction() {
		$pk = $this->pk;
		$resultado = array();
		try {
			$registro = $this->getBean();
			$id = $this->persisteInsere($registro);
			
			$resultado[$pk] = $id;
			$resultado['msg'] = 'Inserido com sucesso!';
			$sucesso = true;
		}
		catch (Exception $e) {
			$sucesso = false;
			$resultado['msg'] = 'Erro: ' . $e->getMessage();
			$resultado['errno'] = $e->getCode();
		}
		$resultado['resultado'] = $sucesso;
		
		$this->resultadoInsere($resultado);
	}
	/**
	 * Realiza a persistência do registro na hora de inserir.
	 * @param array $registro Campos a serem inserido
	 * @throws Exception Caso haja algum erro, deve ser lançada uma exceção
	 * @return int A chave primária do registro inserido
	 */
	protected function persisteInsere($registro) {
		$id = $this->modelo->insert($registro);
		return $id;
	}
	/**
	 * Define um comportamento para o resultado da ação de inserir
	 * @param array $resultado {sucesso[, id][, erro]} 
	 */
	protected function resultadoInsere($resultado) {
		$this->resultadoCrud($resultado);
	}
	/**
	 * Edita um registro (Template method)
	 * @param int $_GET['id']
	 * @return
	 * 		bool $this->view->resultado,
	 * 		string $this->view->msg
	 */
	public final function editaAction() {
		$pk = $this->pk;
		$id = $this->_getParam($pk);
		$resultado = array($pk => $id);
//$db = $this->modelo->getAdapter();
//$db->getProfiler()->setEnabled(true);
		try {
			$registro = $this->getBean($id);
			if (!empty($registro)) {
				$this->persisteEdita($registro, $id);
			}
			
			$resultado['msg'] = 'Alterado com sucesso!';
			$sucesso = true;
		}
		catch (Exception $e) {
			$sucesso = false;
			$resultado['msg'] = 'Erro: ' . $e->getMessage();
			$resultado['errno'] = $e->getCode();
		}
//print $db->getProfiler()->getLastQueryProfile()->getQuery();
//print_r($db->getProfiler()->getLastQueryProfile()->getQueryParams());
//$db->getProfiler()->setEnabled(false);
		
		$resultado['resultado'] = $sucesso;
		
		$this->resultadoEdita($resultado);
	}
	/**
	 * Realiza a persistência do registro na hora de editar.
	 * @param array $registro Campos a serem inserido
	 * @param array|int $campos Um array de campos de consulta ou o valor da chave primária do registro a ser editado
	 * @throws Exception Caso haja algum erro, deve ser lançada uma exceção
	 */
	protected function persisteEdita($registro, $campos) {
		if (is_array($campos)) {
			foreach ($campos as $campo => $valor) {
				$where[] = $this->modelo->getAdapter()->quoteInto($campo . ' = ?', $valor);
			}
			$where = implode(' AND ', $where);
		}
		else {
			$where = $this->modelo->getAdapter()->quoteInto($this->pk . ' = ?', $campos);
		}
		return $this->modelo->update($registro, $where);
	}
	/**
	 * Define um comportamento para o resultado da ação de editar
	 * @param array $resultado {sucesso[, id][, erro]} 
	 */
	protected function resultadoEdita($resultado) {
		$this->resultadoCrud($resultado);
	}
	
	/**
	 * Apaga um registro (Template method)
	 * @param int $_GET['id']
	 * @return int $this->view->total O número de linhas apagadas
	 * @return bool $this->view->resultado
	 * @return string $this->view->msg
	 */
	public final function apagaAction() {
		$pk = $this->pk;
		$id = $this->_getParam($pk);
		$resultado = array();
		
		try {
			$total = $this->persisteApaga($id);
			$sucesso = true;
			$resultado['total'] = $total;
			$resultado['msg'] = 'Apagado com sucesso!';
		}
		catch (Exception $e) {
			$sucesso = false;
			$resultado['msg'] = 'Erro: ' . $e->getMessage();
		}
		
		$resultado[$pk] = $id;
		$resultado['resultado'] = $sucesso;
		
		$this->resultadoApaga($resultado);
	}
	/**
	 * Realiza a persistência do registro na hora de apagar.
	 * @param int $id A chave primária do registro a ser apagado
	 * @throws Exception Caso haja algum erro, deve ser lançada uma exceção
	 */
	protected function persisteApaga($id) {
		
		$camposUploads = (!empty($this->uploads)) ? array_keys($this->uploads) : array();
		$where = $this->modelo->getAdapter()->quoteInto($this->pk . ' = ?', $id);
//		new d($where);die;
		$total = $this->modelo->delete($where, $camposUploads);
		return $total;
	}
	
	/**
	 * Altera o status do registro
	 */
	function ativaAction(){
		$id = $this->_getParam($this->pk);
		$status = $this->_getParam('status');
		try {
			$this->persisteEdita(array('ativo' => $status), $id);
			$sucesso = true;
			$resultado['msg'] = (($status == 0) ? 'Desa' : 'A') . 'tivado com sucesso!';
		} catch (Exception $e) {
			try {
				$this->persisteEdita(array('status' => $status), $id);
				$sucesso = true;
				$resultado['msg'] = (($status == 0) ? 'Desa' : 'A') . 'tivado com sucesso!';
			}
			catch (Exception $e) {
				$sucesso = false;
				$resultado['msg'] = 'Erro: ' . $e->getMessage();
			}
		}
		$resultado['resultado'] = $sucesso;
		$this->resultadoEdita($resultado);
	}
	
	/**
	 * Define um comportamento para o resultado da ação de apagar
	 * @param array $resultado {sucesso[, total][, erro]} 
	 */
	protected function resultadoApaga($resultado) {
		$this->resultadoCrud($resultado);
	}

	/**
	 * Define um comportamento padrão para o resultado das ações de inserir/editar/apagar
	 * @param array $resultado {sucesso[, id][, erro]} 
	 */
	protected function resultadoCrud($resultado) {
		if ($this->getRequest()->isXmlHttpRequest() || !empty($_REQUEST['IS_XML_HTTP_REQUEST'])) {
			$this->_helper->viewRenderer->setNoRender();
			echo json_encode($resultado);
		}
		$this->resultado($resultado);
	}
	
	// Métodos relativos a upload
	/**
	 * Gancho anterior upload
	 * @param Bean $campos
	 */
	protected function beforeUpload(&$campos){
	}
	/**
	 * Lida o upload de arquivos dos campos definidos
	 * @param Bean $campos
	 * @param int $id OPCIONAL
	 */
	protected function trataUploads(&$campos, $id = 0) {
//new d($this->uploads);die;
		if (!empty($this->uploads)) {
			foreach ($this->uploads as $campo => $opcoes) {
				$campos[$campo] = array();
				$caminho = $this->caminho;
				
				if (!empty($opcoes['caminho'])) {
					$caminho .= $opcoes['caminho'];
				}
				
				// trata o novo arquivo
			// verifica se tem um arquivo válido
//var_dump($caminho);
//var_dump($opcoes);
				$filesName = $_FILES[$campo]['name'];
				
				foreach((array)$filesName as $file){
					if(!empty($file)){
						$temArquivo = true; break;
					}
				}
				
				if ((!is_array($filesName) && !empty($filesName)) || (is_array($filesName) && $temArquivo)) {
						$adapter = new Zend_File_Transfer_Adapter_Http();
						if(!empty($opcoes['validacoes'])){
							$adapter->setValidators($opcoes['validacoes']);
						}
						$adapter->setDestination($caminho);
	
						foreach ($adapter->getFileInfo($campo) as $arquivo => $info) {
							if(!empty($info['name'])){
								$adapter->clearFilters();
		
								if($opcoes['nome'] != '/nao-renomeie/'){
									if(empty($opcoes['nome'])){
										$hoje	= date('Ymd-His');
										$id		= uniqid();
										$nome_arquivo	= $hoje . '-' . $id;
										$nome_gravacao	= $nome_arquivo;
									}
									else{
										$nome_gravacao = $opcoes['nome'];
									}
									$ext = end(explode('.', $info['name']));
									$nome_gravacao .= '.' . $ext;
									$adapter->addFilter('Rename', $nome_gravacao, $arquivo);
								}
								
								if (!$adapter->isUploaded($arquivo)) {
									throw new Exception('Não conseguiu fazer upload: ' . $this->erroToString($info['error']) . ' | ' . json_encode($adapter->getMessages()));
								}
								if (!$adapter->isValid($arquivo)) {
									throw new Exception('Não é um arquivo válido: ' . $this->erroToString($info['error']) . ' | ' . json_encode($adapter->getMessages()));
								}	
								if (!$adapter->receive($arquivo)) {
									throw new Exception('Algum erro na hora de mover o arquivo: ' . $this->erroToString($info['error']) . ' | ' . json_encode($adapter->getMessages()));
								}
		
								
								if ($opcoes['nomeOriginal']) {
									$campos[$campo][$info['name']] = $nome_gravacao;
								}
								else {
									//new d($novoArquivo);
									$campos[$campo][] = $nome_gravacao;
								}
							}
						// TODO verifica se quer apagar o arquivo antigo
						}
					}
	//var_dump(4);
					
					// trata edição
					/*
					 *  TODO
					 *  	ve se já tem arquivo
					 *  	confere se é diferente
					 *  	apaga arquivos diferentes
					 */
					if ($id != 0) {
						if (!empty($campos['apagar_' . $campo])) {
							try {
								$r = $this->modelo->fetchRow($this->pk . ' = ' . $id);
								$this->modelo->update(array($campo => ''), $this->pk . ' = ' . $id);
								unset($campos['apagar_' . $campo]);
								$arquivo = $caminho . $r->$campo;
								if (file_exists($arquivo) && is_file($arquivo)) {
									unlink($arquivo);
								}
							}
							catch (Exception $e){
								unset($campos['apagar_' . $campo]);
							}
						}
					}
					
					switch (count($campos[$campo])) {
						case 0:
							unset($campos[$campo]);
							break;
						case 1:
							if ($opcoes['nomeOriginal']) {
								$campos[$campo][$info['name']] = $nome_gravacao;
							}
							else {
								//new d($novoArquivo);
							$campos[$campo] = current($campos[$campo]);
							}
							//$campos[$campo] = current($campos[$campo]);
					}
			}
		}
		return $campos;
	}
	/**
	 * Traduz o código de erro para texto
	 * @param $error_code
	 * @return string
	 */
	protected function erroToString($error_code) {
		switch ($error_code) { 
			case UPLOAD_ERR_OK: 
				return 'There is no error, the file uploaded with success.'; 
			case UPLOAD_ERR_INI_SIZE: 
				return 'The uploaded file exceeds the upload_max_filesize directive in php.ini'; 
			case UPLOAD_ERR_FORM_SIZE:  
				return 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'; 
			case UPLOAD_ERR_PARTIAL: 
				return 'The uploaded file was only partially uploaded'; 
			case UPLOAD_ERR_NO_FILE: 
				return 'No file was uploaded'; 
			case UPLOAD_ERR_NO_TMP_DIR: 
				return 'Missing a temporary folder'; 
			case UPLOAD_ERR_CANT_WRITE: 
				return 'Failed to write file to disk'; 
			case UPLOAD_ERR_EXTENSION: 
				return 'File upload stopped by extension'; 
			default: 
				return 'Unknown upload error';
		}
	}
}